/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/igfx/EPSInterface.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

namespace gfxinterface
{

CEPSInterface::CEPSInterface()
: CFileGfxInterface()
{
	InitState();
}

CEPSInterface::~CEPSInterface()
{
}


void CEPSInterface::InitState()
{
	memset(&m_state.strokecol,0,sizeof(SRGBA));
	memset(&m_state.fillcol,1,sizeof(SRGBA));
	memset(&m_state.m_cShadow,0,sizeof(SRGBA));
	m_state.m_cShadow.a=0.3;
	m_state.strokecol.a=1;
	m_state.dash=_T("");
	m_state.linewidth=0;

	m_state.m_eFillType = SEPSState::SolidFill;
	m_state.m_sLinearGradient.m_cStart=SRGBA(0,0,0,1);
	m_state.m_sLinearGradient.m_cEnd=SRGBA(1,1,1,1);
	m_state.m_sLinearGradient.m_pStart=SPointD(0,0);
	m_state.m_sLinearGradient.m_pEnd=SPointD(1,1);

	m_lStates.clear();
}

void CEPSInterface::WriteHeader()
{
	double sqrt3=sqrt(3.0);
	TCHAR tzBuffer[256];
	time_t t;
	struct tm* timeLocal;
	time(&t);
	timeLocal=localtime(&t);
	_tcsftime(tzBuffer, 256, _T("%d/%m/%Y, %H:%M:%S"), timeLocal);

	m_stream<<_T("%!PS_Adobe-3.0 EPSF-3.0\n");
	m_stream<<_T("%%Creator:")<<GetCreator()<<std::endl;
	m_stream<<_T("%%Title:")<<GetTitle()<<std::endl;
	m_stream<<_T("%%CreationDate:")<<tzBuffer<<std::endl;

	m_stream<<_T("%%BoundingBox:")<<GetBBLeft()<<_T(" ")<<GetBBBottom()<<_T(" ")
		<<GetBBRight()<<_T(" ")<<GetBBTop()<<std::endl;
	m_stream<<_T("%%LanguageLevel: 2\n");
	m_stream<<_T("% World Bounding Box : ")<<GetWorldLeft()<<_T(" ")<<GetWorldBottom()<<_T(" ")
		<<GetWorldRight()<<_T(" ")
		<<GetWorldHeight()<<std::endl;
	AddComment(_T("------------------------------------------------------------------------------"));
	AddComment(_T("Begin Operators Definitions:"));
	AddComment(_T("Name, description, stack state"));
	AddComment(_T("------------------------------------------------------------------------------"));

	AddComment(_T("----------------"));
	AddComment(_T("EWLeftShow, left aligned text, text"));
	m_stream<<_T("/EWLeftShow {show} def\n");

	AddComment(_T("----------------"));
	AddComment(_T("EWRightShow, right aligned text, text"));
	m_stream<<_T("/EWRightShow { dup stringwidth pop -1 mul 0 rmoveto show } def\n");

	AddComment(_T("----------------"));
	AddComment(_T("EWCenterShow, centered text, text"));
	m_stream<<_T("/EWCenterShow { dup stringwidth pop -0.5 mul 0 rmoveto show } def\n");

	AddComment(_T("----------------"));
	AddComment(_T("EWDownCenterShow, centered text down of cursor, text"));
	m_stream<<_T("/EWDownCenterShow { dup stringwidth pop -0.5 mul exch neg rmoveto show } def\n");

	AddComment(_T("----------------"));
	AddComment(_T("EWBox, startx starty dx dy"));
	m_stream<<_T("/EWBox {/dy exch def /dx exch def newpath moveto 0 dy rlineto dx 0 rlineto 0 dy -1 mul rlineto closepath} def\n");

	AddComment(_T("----------------"));
	AddComment(_T("EWStockOHLC, stock chart: (bar x position) (bar width) open high low close"));
	m_stream<<_T("/EWStockOHLC { ")
		<<_T("/myClose exch def /myLow exch def /myHigh exch def /myOpen exch def /myBarw exch def /myBarx exch def newpath ")
		<<_T("myBarx myOpen moveto myBarw neg 0 rlineto ")
		<<_T("myBarx myLow moveto myBarx myHigh lineto ")
		<<_T("myBarx myClose moveto myBarw 0 rlineto ")		
		<<_T(" stroke } def\n");

	AddComment(_T("---------------------"));
	AddComment(_T("EWErrorBarAV, error bar absolute vertical, x, down,up, width"));
	m_stream<<_T("/EWErrorBarAV { ")
		<<_T("/w exch def /up exch def /down exch def /x exch def ")
		<<_T("x w 2 div sub down moveto w 0 rlineto ")
		<<_T("x down moveto x up lineto ")
		<<_T("x w 2 div sub up moveto w 0 rlineto ")
		<<_T(" stroke } def\n");

	AddComment(_T("---------------------"));
	AddComment(_T("EWErrorBarAH, error bar absolute horizontal, y, left,right, width"));
	m_stream<<_T("/EWErrorBarAH { ")
		<<_T("/w exch def /right exch def /left exch def /y exch def ")
		<<_T("left y w 2 div sub moveto 0 w rlineto ")
		<<_T("left y moveto right y lineto ")
		<<_T("right y w 2 div sub moveto 0 w rlineto ")
		<<_T(" stroke } def\n");

	AddComment(_T("---------------------"));
	AddComment(_T("EWErrorBarRV, error bar relative vertical, x, y, down,up, width"));
	m_stream<<_T("/EWErrorBarRV { ")
		<<_T("/w exch def /u exch def /d exch def /y exch def /x exch def y d sub /down exch def y u add /up exch def ")
		<<_T("x w 2 div sub down moveto w 0 rlineto ")
		<<_T("x down moveto x up lineto ")
		<<_T("x w 2 div sub up moveto w 0 rlineto ")
		<<_T(" stroke } def\n");

	AddComment(_T("---------------------"));
	AddComment(_T("EWErrorBarRH, error bar relative horizontal, x, y, left,right, width"));
	m_stream<<_T("/EWErrorBarRH { ")
		<<_T("/w exch def /r exch def /l exch def /y exch def /x exch def  x l sub /left exch def x r add /right exch def ")
		<<_T("left y w 2 div sub moveto 0 w rlineto ")
		<<_T("left y moveto right y lineto ")
		<<_T("right y w 2 div sub moveto 0 w rlineto ")
		<<_T(" stroke } def\n");

	AddComment(_T("EWArrow, an arrow, tailx taily tipx tipy tailthickness headthickness headlength"));
	AddComment(_T("See Postscript language Cookbook, Program 4"));
	AddComment(_T("Setting arrow dictionnary"));
	m_stream<<_T("/EWArrowDict 14 dict def EWArrowDict begin /mtrx matrix def end\n");	
	AddComment(_T("Defining arrow procedure"));
	m_stream<<_T("/EWArrow { EWArrowDict begin ")
		<<_T("/headlength exch def /halfheadthickness exch 2 div def /halfthickness exch 2 div def ")
		<<_T("/tipy exch def /tipx exch def /taily exch def /tailx exch def ")
		<<_T("/dx tipx tailx sub def /dy tipy taily sub def ")
		<<_T("/arrowlength dx dx mul dy dy mul add sqrt def ")
		<<_T("/angle dy dx atan def /base arrowlength headlength sub def ")
		<<_T("/savematrix mtrx currentmatrix def ")
		<<_T("tailx taily translate angle rotate ")
		<<_T("0 halfthickness neg moveto base halfthickness neg lineto ")
		<<_T("base halfheadthickness neg lineto arrowlength 0 lineto ")
		<<_T("base halfheadthickness lineto base halfthickness lineto " )
		<<_T("0 halfthickness lineto closepath ")
		<<_T("savematrix setmatrix end }def\n");
	AddComment(_T("End Preliminary Definitions"));
	AddComment(_T("------------------------------------------------------------------------------\n"));
}

void CEPSInterface::BeginPaint(HDC hDC)
{
	CFileGfxInterface::BeginPaint(hDC);

	// init state
	InitState();
	// init EPS header
	WriteHeader();

	m_stream<<_T("gsave\n");
}

void CEPSInterface::EndPaint()
{
	m_stream<<_T("grestore\n");

	CFileGfxInterface::EndPaint();
}

void CEPSInterface::DrawLineStrip(const CVectorF& vX, const CVectorF& vY,  DWORD eLineTypeFlag, double dTension)
{
	const size_t n = __min( vX.size(), vY.size());
	if (n==0)
		return;

	int count=0;
	m_stream<<_T("newpath\n");
	if (eLineTypeFlag & LineTypeSnapBottom)
	{
		m_stream<<WorldToBBx(vX[0])<<_T(" ")<<GetWorldBottom()<<std::endl;
		count++;
	}

	for (size_t i=0;i<n;i++)
	{
		m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vY[i])<<std::endl;
		count++;
	}
	if (eLineTypeFlag & LineTypeSnapBottom)
	{
		m_stream<<WorldToBBx(vX[n-1])<<_T(" ")<<GetWorldBottom()<<std::endl;
		count++;
	}

	m_stream<<_T("moveto ")<<count-1<<_T(" {lineto} repeat ");

	if (eLineTypeFlag & LineTypeFilled)
	{
		PushState();
		m_stream<<_T("closepath clip\n");
		PutFillColorString();
		PopState();
	}

	if ( !(eLineTypeFlag & LineTypeNoContour) )
	{
		if (eLineTypeFlag & LineTypeClosed  && n>2)	
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
		else
		{
			PutStrokeColorString();
			m_stream<<_T("stroke\n");
		}
	}
}

void CEPSInterface::DrawStepStrip(const CVectorF& vX, const CVectorF& vY, DWORD eLineTypeFlag)
{
	const size_t n = __min( vX.size(), vY.size());
	if (n==0)
		return;

	int count=0;

	m_stream<<_T("newpath\n");
	if (eLineTypeFlag & LineTypeSnapBottom)
	{
		m_stream<<WorldToBBx(vX[0])<<_T(" ")<<GetWorldBottom()<<std::endl;
		count++;
	}

	for (size_t i=0;i<n-1;i++)
	{
		m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vY[i])<<_T(" ");
		m_stream<<WorldToBBx(vX[i+1])<<_T(" ")<<WorldToBBy(vY[i])<<std::endl;
		count+=2;
	}

	if (eLineTypeFlag & LineTypeSnapBottom)
	{
		m_stream<<WorldToBBx(vX[n-1])<<_T(" ")<<GetWorldBottom()<<std::endl;
		count++;
	}

	m_stream<<_T("moveto ")<<count-1<<_T(" {lineto} repeat ");

	if (eLineTypeFlag & LineTypeFilled)
	{
		PushState();
		m_stream<<_T("closepath ");
		PutFillColorString();
		PopState();
	}

	if ( !(eLineTypeFlag & LineTypeNoContour) )
	{
		if (eLineTypeFlag & LineTypeClosed)	
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
		else
		{
			PutStrokeColorString();
			m_stream<<_T("stroke\n");
		}
	}
}

void CEPSInterface::DrawBandStrip(const CVectorF& vX, const CVectorF& vYBottom, const CVectorF& vYTop, DWORD eBandTypeFlag, double dTension)
{
	const int n = __min( vX.size(), __min(vYBottom.size(), vYTop.size()));
	if (n==0)
		return;

	std::valarray<float> vY(n);

	int i;
	int count=0;
	m_stream<<_T("newpath\n");

	if (eBandTypeFlag & BandTypeAbsolute)
	{
		for (i=0;i<n;i++)
		{
			m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vYBottom[i])<<std::endl;
			count++;
		}
		for (i=n-1;i>=0;i--)
		{
			vY[i]=vYTop[i];
			m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vY[i])<<std::endl;
			count++;
		}
	}
	else
	{
		for (i=0;i<n;i++)
		{
			m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vYBottom[i])<<std::endl;
			count++;
		}
		for (i=n-1;i>=0;i--)
		{
			vY[i]=vYBottom[i]+vYTop[i];
			m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vY[i])<<std::endl;
			count++;
		}
	}
	m_stream<<_T("moveto ")<<count-1<<_T(" {lineto} repeat ");

	// filling
	if ( !(eBandTypeFlag & BandTypeNotFilled) )
	{
		PushState();
		m_stream<<_T("closepath ");
		PutFillColorString();		
		PopState();
	}

	// drawing line
	if ( !(eBandTypeFlag & BandTypeNoContour) )
	{
		if (eBandTypeFlag & BandTypeFullContour)	
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
		else if (eBandTypeFlag & BandTypeLowerLineOnly)	
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
		else if (eBandTypeFlag & BandTypeUpperLowerLine)	
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
		else
		{
			PutStrokeColorString();
			m_stream<<_T("closepath stroke\n");		
		}
	}

}

void CEPSInterface::DrawMultipleLineStrip(int ns, const CVectorF& vX, const CVectorF& vY, DWORD eLineTypeFlag)
{
	const int n = __min( vX.size(), vY.size());
	if (n==0)
		return;

	int count, nscur;
	int index = 0;

	do
	{
		count=0;
		nscur=__min(ns,n-index);
		m_stream<<_T("newpath\n");
		if (eLineTypeFlag & LineTypeSnapBottom)
		{
			m_stream<<WorldToBBx(vX[index])<<_T(" ")<<GetWorldBottom()<<std::endl;
			count++;
		}
	
		for (int i=index;i<index+nscur;i++)
		{
			m_stream<<WorldToBBx(vX[i])<<_T(" ")<<WorldToBBy(vY[i])<<std::endl;
			count++;
		}

		if (eLineTypeFlag & LineTypeSnapBottom)
		{
			m_stream<<WorldToBBx(vX[index+nscur-1])<<_T(" ")<<GetWorldBottom()<<std::endl;
			count++;
		}
	
		m_stream<<_T("moveto ")<<count-1<<_T(" {lineto} repeat ");
	
		if (eLineTypeFlag & LineTypeFilled)
		{
			PushState();
			m_stream<<_T("closepath ");
			PutFillColorString();
			PopState();
		}
	
		if ( !(eLineTypeFlag & LineTypeNoContour) )
		{
			if (eLineTypeFlag & LineTypeClosed)	
			{
				PutStrokeColorString();
				m_stream<<_T("closepath stroke\n");		
			}
			else
			{
				PutStrokeColorString();
				m_stream<<_T("stroke\n");
			}
		}

		// udpating index...
		index+=ns;
	} while (index<n);
	
}

void CEPSInterface::AddComment(LPCTSTR str)
{
#ifdef _DEBUG
	m_stream<<_T("%")<<str<<std::endl;
#endif
}

void CEPSInterface::SetColor(double r, double g, double b, double a)
{
	m_state.strokecol.r = __max(0, __min( 1, r));
	m_state.strokecol.g = __max(0, __min( 1, g));
	m_state.strokecol.b = __max(0, __min( 1, b));
	m_state.strokecol.a = __max(0, __min( 1, a));
}

void CEPSInterface::SetFillColor(double r, double g, double b, double a)
{
	m_state.fillcol.r = __max(0, __min( 1, r));
	m_state.fillcol.g = __max(0, __min( 1, g));
	m_state.fillcol.b = __max(0, __min( 1, b));
	m_state.fillcol.a = __max(0, __min( 1, a));
}

void CEPSInterface::SetShadowColor(double r, double g, double b, double a)
{
	m_state.m_cShadow.r = __max(0, __min( 1, r));
	m_state.m_cShadow.g = __max(0, __min( 1, g));
	m_state.m_cShadow.b = __max(0, __min( 1, b));
	m_state.m_cShadow.a = __max(0, __min( 1, a));
}

void CEPSInterface::SetLinearGradientFill(const SPointD& point1, const SPointD& point2, const SRGBA& col1, const SRGBA& col2)
{	
	m_state.m_sLinearGradient.m_cStart=col1;
	m_state.m_sLinearGradient.m_cEnd=col2;
	m_state.m_sLinearGradient.m_pStart=point1;
	m_state.m_sLinearGradient.m_pEnd=point2;
	m_state.m_eFillType = SEPSState::LinearGradientFill;
};

void CEPSInterface::SetDash(LPCTSTR dash)
{
	if (dash!= m_state.dash)
	{
		m_state.dash=dash;
		m_stream<<_T("[")<<dash<<_T("] 0 setdash\n");
	}
}

void CEPSInterface::DrawLine(double x1, double y1, double x2, double y2)
{
	PutStrokeColorString();
	m_stream<<_T("newpath ")<<WorldToBBx(x1)<<_T(" ")<<WorldToBBy(y1)<<_T(" moveto ")
		<<WorldToBBx(x2)<<_T(" ")<<WorldToBBy(y2)<<_T(" lineto stroke\n");
}

void CEPSInterface::DrawText(double x, double y, LPCTSTR str, ETextAlignment ta, double angle)
{
	if (_tcsclen(str) == 0)
		return;

	PutStrokeColorString();
	m_stream<<WorldToBBx(x)+sin(angle)*abs(m_state.font.lfHeight)<<_T(" ")<<WorldToBBy(y)+cos(angle)*abs(m_state.font.lfHeight)<<_T(" moveto ");
	// rotating if needed
	if (angle)
		m_stream<<angle<<_T(" rotate ");

	m_stream<<_T("(")<<str<<_T(") ");
	
	switch (ta)
	{
	case TextAlignmentLeft:
		m_stream<<_T("show ");
		break;
	case TextAlignmentCenter:
		m_stream<<_T("EWCenterShow ");
		break;
	case TextAlignmentRight:
		m_stream<<_T("EWRightShow ");
		break;
	}

	// rotating back
	if (angle)
		m_stream<<-angle<<_T(" rotate ");
	m_stream<<std::endl;	
}

void CEPSInterface::DrawTextStrip(const std::vector<SPointD>& vPoints, const std::vector<std::_tstring>& vStrings, ETextAlignment ta, double angle)
{
    size_t n = std::min(vPoints.size(), vStrings.size());
	PutStrokeColorString();
	
	for (size_t i=0; i<n;i++)
	{
 		m_stream<<WorldToBBx(vPoints[i].x)+sin(angle)*abs(m_state.font.lfHeight)<<_T(" ")
 			<<WorldToBBy(vPoints[i].y)+cos(angle)*abs(m_state.font.lfHeight)<<_T(" moveto ");
		// rotating if needed
		if (angle)
			m_stream<<angle<<_T(" rotate ");

		m_stream<<_T("(")<<vStrings[i].c_str()<<_T(") ");
		switch(ta)
		{
		case TextAlignmentLeft:
			m_stream<<_T("EWLeftShow ");
			break;
		case TextAlignmentCenter:
			m_stream<<_T("EWCenterShow ");
			break;
		case TextAlignmentRight:
			m_stream<<_T("EWRightShow ");
			break;
		default:
			ASSERT(FALSE);
		}
		// rotating back
		if (angle)
			m_stream<<-angle<<_T(" rotate ");
		m_stream<<std::endl;	
	}	
};


void CEPSInterface::SetFont(const LOGFONT& logFont)
{
	m_state.font=logFont;
 	m_stream<<_T("/Times-Roman findfont ")<<abs(logFont.lfHeight)+4<<_T(" scalefont setfont\n");
}


void CEPSInterface::DrawCircle(double cx, double cy, double dRadius, DWORD eLineType)
{
	DefineCircle(dRadius, eLineType);

	m_stream<<WorldToBBx(cx)<<_T(" ")<<WorldToBBy(cy)<<_T(" ")<<_T(" EWCircle\n");
}

void CEPSInterface::DefineCircle(double dRadius, DWORD eLineType)
{
	m_stream<<_T("/EWCircle {\n");
	// start definition
	m_stream<<dRadius<<_T(" 0 360 arc\n"); 

	// fill if needed
	if (eLineType & LineTypeFilled)
	{
		PushState();
			m_stream<<_T("clip\n");
			PutFillColorString();
		PopState();
	}


	if (eLineType & LineTypeShadow)
	{
		PushState();
			m_stream<<m_state.linewidth+1<<_T(" ")<<m_state.linewidth+1<<_T(" translate\n");
			m_stream<<_T("0.3 0.3 0.3 setrgbcolor\n");
			m_stream<<_T("stroke\n");		
		PopState();
	}

	// contour if needed
	if ( ! (eLineType & LineTypeNoContour) )
	{
		// draw contour
		PutStrokeColorString();
		m_stream<<_T("stroke ");
	}

	// end definition
	m_stream<<_T("} def\n");
}

void CEPSInterface::DrawCircleStrip(const CVectorF& vCx, const CVectorF& vCy, double dRadius, DWORD eLineType)
{
	const int n = __min(vCx.size(), vCy.size());
	if (n==0)
		return;

	for (int i=0;i<n;i++)
	{
		m_stream<<WorldToBBx(vCx[i])<<_T(" ")<<WorldToBBy(vCy[i])<<std::endl;
	}

	DefineCircle(dRadius, eLineType);

	m_stream<<n<<_T(" { EWCircle } repeat\n");
}


void CEPSInterface::SetLineWidth(double width)
{
	if (width != m_state.linewidth)
	{
		m_state.linewidth=__max(0,width-1);
		m_stream<<m_state.linewidth<<_T(" setlinewidth\n");
	}
}

void CEPSInterface::DrawSurf(const contour::TLattice<float>& tLattice, const CVectorF& vColor, DWORD dwFlag)
{
/*
	double xCur,yCur;
	int i,j,k;
	ASSERT( nx*ny*3 == vColor.size());
	AddComment(_T("Drawing surface"));
	AddComment(_T("Init shading dictionnary"));
	m_stream<<_T("/DeviceRGB setcolorspace\n");

	AddComment(_T("Define the shading dictionary"));
	m_stream<<_T(")<<\n/ShadingType 5\n/ColorSpace /DeviceRGB\n")
		<<_T("/VerticesPerRow ")<<nx<<_T(" \n/DataSource [\n");

	// sending points by rows
	yCur=uly;
	k=0;
	for (i=0;i<ny;i++)
	{
		xCur=llx;
		for (j=0;j<nx;j++)
		{
			_ASSERT(k==i*nx+j);
			// sending to postscript
			m_stream<<WorldToBBx(xCur)<<_T(" ")<<WorldToBBy(yCur)<<_T(" ")
				<<vColor[k*3]<<_T(" ")
				<<vColor[k*3+1]<<_T(" ")
				<<vColor[k*3+2]<<std::endl;
			// updating xCur
			xCur += dx;
			k++;
		}
		// updating y
		yCur-=dy;
	}
	// stroking
	m_stream<<_T("]\n>> shfill\n");


	if (dwFlag & ESurfWireFrame)
	{
		DrawGridHor(llx, llx+(nx-1)*dx, uly-(ny-1)*dy, uly,dy);
		DrawGridVer(llx, llx+(nx-1)*dx, uly-(ny-1)*dy, uly,dx);
	}
*/
}

void CEPSInterface::DrawVectorField(const contour::TLattice<float>& tLattice, const CVectorF& vVx, const CVectorF& vVy, float fScale, DWORD dwFlags)
{
/*
	double xCur,yCur;
	int i,j,k,lcount;

	lineWidth = __max(1, lineWidth);
	// draw contour
	PutStrokeColorString();
	AddComment(_T("Vector field"));
	m_stream<<_T("newpath\n");
	// sending points by rows
	yCur=lly+(ny-1)*dy;
	k=0;
	lcount=0;
	for (i=0;i<ny;i++)
	{
		xCur=llx;
		for (j=0;j<nx;j++)
		{
			_ASSERT(k==i*nx+j);
			if (sqrt( vV[k*2]*vV[k*2]+vV[k*2+1]*vV[k*2+1] ) > 1e-10)
			{
				// sending to postscript
				m_stream<<WorldToBBx(xCur-vV[k*2]/2)<<_T(" ")<<WorldToBBy(yCur-vV[k*2+1]/2)<<_T(" ")
					<<WorldToBBx(xCur+vV[k*2]/2)<<_T(" ")<<WorldToBBy(yCur+vV[k*2+1]/2)<<_T(" ")
					<<lineWidth<<_T(" 4.0 6.0")<<std::endl;
				lcount++;
			}
			// updating xCur
			xCur+=dx;
			k++;
		}
		yCur-=dy;
	}
	m_stream<<lcount<<_T(" {EWArrow} repeat fill")<<std::endl;
*/
}

void CEPSInterface::PushClipWorld(double llx, double lly, double urx, double ury)
{
	CFileGfxInterface::PushClipWorld(llx,lly,urx,ury);

	m_stream<<_T(" gsave ");
	// clipping path...
	m_stream<<WorldToBBx(llx)<<_T(" ")
		<<WorldToBBy(lly)<<_T(" ")
		<<WorldToBBAbsx(urx-llx)<<_T(" ")
		<<WorldToBBAbsy(ury-lly)<<_T(" ")
		<<_T("rectclip\n");
}

void CEPSInterface::PopClipWorld()
{
	CFileGfxInterface::PopClipWorld();

	m_stream<<_T(" grestore\n");
}

void CEPSInterface::PushState()
{
	m_stream<<_T(" gsave\n");
	m_lStates.push_front(m_state);
}

void CEPSInterface::PopState()
{
	ASSERT(!m_lStates.empty());
	m_state = m_lStates.front();
	m_lStates.pop_front();
	m_stream<<_T(" grestore\n");
}

void CEPSInterface::Fill()
{
	m_stream<<_T(" fill\n");
}

void CEPSInterface::DrawGridHor(double llx, double urx, double lly, double ury,double dy)
{
	AddComment(_T("Drawing horizontal grid"));
	double y=lly;
	
	int count;
	PutStrokeColorString();
	// Drawing lines
	m_stream<<_T("newpath\n");
	// sending points
	count=0;
	y=lly;
	m_stream<<WorldToBBx(urx)<<_T(" ")<<WorldToBBy(y)<<_T(" moveto")<<std::endl;
	while (y<ury-dy)
	{
		m_stream<<WorldToBBAbsx(urx-llx)<<_T(" 0 ")<<-WorldToBBAbsx(urx-llx)<<_T(" ")<<WorldToBBAbsy(dy)<<std::endl;
		count++;
		y+=dy;
	}

	m_stream<<count<<_T(" {rmoveto rlineto} repeat stroke\n");
}

void CEPSInterface::DrawGridVer(double llx, double urx, double lly, double ury,double dx)
{
	AddComment(_T("Drawing vertical grid"));
	double x=llx;
	
	int count;
	PutStrokeColorString();
	// Drawing lines
	m_stream<<_T("newpath\n");
	// sending points
	count=0;
	x=llx;
	m_stream<<WorldToBBx(x)<<_T(" ")<<WorldToBBy(ury)<<_T(" moveto")<<std::endl;
	while (x<urx-dx)
	{
		m_stream<<_T("0 ")<<WorldToBBAbsy(ury-lly)<<_T(" ")<<WorldToBBAbsx(dx)<<_T(" ")<<-WorldToBBAbsy(ury-lly)<<std::endl;
		count++;
		x+=dx;
	}

	m_stream<<count<<_T(" {rmoveto rlineto} repeat stroke\n");
}

void CEPSInterface::DrawArrow(double tailx, double taily, double tipx, double tipy, double tailthickness, double headthickness, double headlength, bool filled)
{
	m_stream<<WorldToBBx(tailx)<<_T(" ")<<WorldToBBy(taily)<<_T(" ")<<WorldToBBx(tipx)<<_T(" ")<<WorldToBBy(tipy)<<_T(" ")<<tailthickness<<_T(" ")<<headthickness<<_T(" ")<<headlength<<_T(" EWArrow ");
	if (filled)
	{	
		PushState();
		PutStrokeColorString();
		PopState();
	}
	PutStrokeColorString();
	m_stream<<_T("stroke\n");
}

void CEPSInterface::DrawArrowAbs(double tailx, double taily, double dtipx, double dtipy, double tailthickness, double headthickness, double headlength, bool filled)
{
	m_stream<<WorldToBBx(tailx)<<_T(" ")<<WorldToBBy(taily)<<_T(" ")<<WorldToBBx(tailx)+dtipx<<_T(" ")<<WorldToBBy(taily)+dtipy<<_T(" ")<<tailthickness<<_T(" ")<<headthickness<<_T(" ")<<headlength<<_T(" EWArrow ");
	if (filled)
	{	
		PushState();
		PutStrokeColorString();
		PopState();
	}
	PutStrokeColorString();
	m_stream<<_T("stroke\n");
}

void CEPSInterface::DrawRect(double llx, double lly, double urx, double ury, DWORD dwRectFlag , SPointD sShadowSize)
{
	m_stream<<_T("newpath ")<<WorldToBBx(llx)<<_T(" ")<<WorldToBBy(ury)<<_T(" ")
		<<WorldToBBx(urx)<<_T(" ")<<WorldToBBy(ury)<<_T(" ")
		<<WorldToBBx(urx)<<_T(" ")<<WorldToBBy(lly)<<_T(" ")
		<<WorldToBBx(llx)<<_T(" ")<<WorldToBBy(lly)<<_T(" moveto 3 {lineto} repeat closepath ");

	if ( dwRectFlag & RectTypeFilled )
	{
		PushState();		
			m_stream<<_T("clip\n");
			PutFillColorString();
		PopState();
	}

	if ( !( dwRectFlag & RectTypeNoContour) )
	{
		PutStrokeColorString();
		m_stream<<_T("stroke\n");		
	}
}

void CEPSInterface::PutFillColorString()
{
	switch(m_state.m_eFillType)
	{
	case SEPSState::SolidFill:
		m_stream<<m_state.fillcol.r<<_T(" ")<<m_state.fillcol.g<<_T(" ")<<m_state.fillcol.b<<_T(" setrgbcolor fill\n");
		break;
	case SEPSState::LinearGradientFill:
		m_stream<<_T("<< /ShadingType 2 /ColorSpace /DeviceRGB\n")
			<<_T("/AntiAlias true\n")
			<<_T("/Coords [")
				<<WorldToBBx(m_state.m_sLinearGradient.m_pStart.x)<<_T(" ")
				<<WorldToBBy(m_state.m_sLinearGradient.m_pStart.y)<<_T(" ")
				<<WorldToBBx(m_state.m_sLinearGradient.m_pEnd.x)<<_T(" ")
				<<WorldToBBy(m_state.m_sLinearGradient.m_pEnd.y)<<_T("]\n")
			<<_T("/Function << /FunctionType 2 /Domain [0 1]\n")
			<<_T("/C0 [")<<m_state.m_sLinearGradient.m_cStart.r<<_T(" ")
				<<m_state.m_sLinearGradient.m_cStart.g<<_T(" ")
				<<m_state.m_sLinearGradient.m_cStart.b<<_T("]\n")
			<<_T("/C1 [")<<m_state.m_sLinearGradient.m_cEnd.r<<_T(" ")
				<<m_state.m_sLinearGradient.m_cEnd.g<<_T(" ")
				<<m_state.m_sLinearGradient.m_cEnd.b<<_T("]\n")
			<<_T("/N 1>>\n>> shfill\n");
		break;
	}
}

void CEPSInterface::PutStrokeColorString()
{
	m_stream<<m_state.strokecol.r<<_T(" ")<<m_state.strokecol.g<<_T(" ")<<m_state.strokecol.b<<_T(" setrgbcolor\n");
}

void CEPSInterface::DrawPolygon(double cx, double cy,  const CVectorF& vPx, const CVectorF& vPy, DWORD eLineType)
{
	const size_t n = __min( vPx.size(), vPy.size());
	if (n==0)
		return;

	AddComment(_T("Drawing polygon"));
	PushState();

	// creating the polygon procedure...
	DefinePolygon(vPx,vPy, eLineType);

	m_stream<<WorldToBBx(cx)<<_T(" ")<<WorldToBBy(cy)<<_T(" polMarker\n");	
	
	PopState();
}

void CEPSInterface::DrawPolygonStrip(const CVectorF& vCx, const CVectorF& vCy,  const CVectorF& vPx, const CVectorF& vPy, DWORD eLineType)
{
	const size_t n = __min( vPx.size(), vPy.size());
	if (n==0)
		return;
	const size_t m = __min( vCx.size(), vCy.size());
	if (m==0)
		return;

	AddComment(_T("Drawing polygons"));
	// creating the polygon procedure...
	DefinePolygon(vPx,vPy, eLineType);

	// adding point in stack
	for (int i=m-1;i>=0;i--)
		m_stream<<WorldToBBx(vCx[i])<<_T(" ")<<WorldToBBy(vCy[i])<<_T("\n");

	m_stream<<m<<_T(" {  polMarker } repeat\n");
}

void CEPSInterface::DefinePolygon(const CVectorF &vx, const CVectorF &vy, DWORD eLineType)
{

	m_stream<<_T("/polMarker {\n");

	// starting definition
	m_stream<<_T("newpath moveto\n");	
    const size_t n = std::min( vx.size(), vy.size());
    if (n<2)
        throw std::exception("Polygon has less that 2 poitns");

	m_stream<<vx[0]<<_T(" ")<<vy[0]<<_T(" rmoveto\n"); 
	for (size_t i=1;i<n;i++)
	{
		m_stream<<vx[i]-vx[i-1]<<_T(" ")<<vy[i]-vy[i-1]<<_T(" rlineto\n"); 
	}

	if (eLineType & LineTypeClosed)
		m_stream<<_T("closepath\n");
	
	if (eLineType & LineTypeFilled)
	{	
		PushState();
			m_stream<<_T("clip\n");
			PutFillColorString();
		PopState();
	}

/*
	if (eLineType & LineTypeShadow)
	{
		PushState();
			m_stream<<_T("5 5 translate\n");
			m_stream<<_T("0.3 0.3 0.3 setrgbcolor\n");
			m_stream<<_T("stroke\n");		
		PopState();
	}
*/
	if (! (eLineType & LineTypeNoContour))
	{
		PutStrokeColorString();
		m_stream<<_T("stroke\n");		
	}


	// ending definition
	m_stream<<_T("} def\n");

}

void CEPSInterface::DrawStock( double x0, double dx, const CVectorF& vHis, const CVectorF& vLows, const CVectorF& vOpens, const CVectorF& vCloses, const SRGBA& cDownColor, DWORD eStockTypeFlag)
{
	const size_t n = __min(vHis.size(), __min( vCloses.size(), __min( vOpens.size(), vLows.size()) ) );
	size_t i,j;
	double x,wdx;

	if (n<2)
		return;

	AddComment(_T("Drawing upgoing stock"));
	PutStrokeColorString();
	x=x0;
	wdx=WorldToBBAbsx(dx/2);

	m_stream<<WorldToBBx(x)<<_T(" ")
		<<wdx<<_T(" ")
		<<WorldToBBy(vOpens[0])<<_T(" ")
		<<WorldToBBy(vHis[0])<<_T(" ")
		<<WorldToBBy(vLows[0])<<_T(" ")
		<<WorldToBBy(vCloses[0])<<_T("\n");
	for (i=1,j=1;i<n;i++)
	{
		x+=dx;
		if (vCloses[i]<vCloses[i-1])
			continue;

		m_stream<<WorldToBBx(x)<<_T(" ")
			<<wdx<<_T(" ")
			<<WorldToBBy(vOpens[i])<<_T(" ")
			<<WorldToBBy(vHis[i])<<_T(" ")
			<<WorldToBBy(vLows[i])<<_T(" ")
			<<WorldToBBy(vCloses[i])<<_T("\n");
		j++;
	}
	m_stream<<j<<_T(" { EWStockOHLC} repeat\n");

	AddComment(_T("Drawing down stock"));
	m_stream<<cDownColor.r<<_T(" ")<<cDownColor.g<<_T(" ")<<cDownColor.b<<_T(" setrgbcolor\n");
	x=x0;
	for (i=1,j=0;i<n;i++)
	{
		x+=dx;
		if (vCloses[i]>=vCloses[i-1])
			continue;

		m_stream<<WorldToBBx(x)<<_T(" ")
			<<wdx<<_T(" ")
			<<WorldToBBy(vOpens[i])<<_T(" ")
			<<WorldToBBy(vHis[i])<<_T(" ")
			<<WorldToBBy(vLows[i])<<_T(" ")
			<<WorldToBBy(vCloses[i])<<_T("\n");
		j++;
	}
	m_stream<<j<<_T(" { EWStockOHLC} repeat\n");

}

void CEPSInterface::DrawErrorBars( const CVectorF& vXs, const CVectorF& vYs, const CVectorF& vUps, const CVectorF& vDowns, double dWidth, bool bAbsolute, bool bVertical)
{
	using namespace Gdiplus;
	size_t n;
	
	if (bAbsolute)
	{
		if (bVertical)
			n=__min(vXs.size(), __min(vUps.size(), vDowns.size()) );
		else
			n=__min(vYs.size(), __min(vUps.size(), vDowns.size()) );
	}
	else
		n=__min(vXs.size(), __min(vYs.size(), __min(vUps.size(), vDowns.size()) ) );

	if (n==0)
		return;

	size_t i;
	CString str;
	float wx,wy,wUp,wDown,wLeft,wRight;
	AddComment(_T("Drawing error bar"));
	PutStrokeColorString();

	str=_T("");
	if (!bAbsolute && bVertical)
	{
		for (i=0;i<n;i++)
		{
			wx=(REAL)WorldToBBx(vXs[i]);
			wy=(REAL)WorldToBBy(vYs[i]);
			wUp=(REAL)WorldToBBAbsy(vUps[i]);
			wDown=(REAL)WorldToBBAbsy(vDowns[i]);

			m_stream<<wx<<_T(" ")<<wy<<_T(" ")<<wDown<<_T(" ")<<wUp<<_T(" ")<<dWidth<<_T("\n");
		}
		m_stream<<n<<_T(" { EWErrorBarRV} repeat\n");
	}
	else if( !bAbsolute && ! bVertical)
	{
		for (i=0;i<n;i++)
		{
			wx=(REAL)WorldToBBx(vXs[i]);
			wy=(REAL)WorldToBBy(vYs[i]);
			wLeft=(REAL)WorldToBBAbsx(vDowns[i]);
			wRight=(REAL)WorldToBBAbsx(vUps[i]);


			m_stream<<wx<<_T(" ")<<wy<<_T(" ")<<wLeft<<_T(" ")<<wRight<<_T(" ")<<dWidth<<_T("\n");
		}
		m_stream<<n<<_T(" { EWErrorBarRH} repeat\n");
	}
	else if (bAbsolute && !bVertical)
	{
		for (i=0;i<n;i++)
		{
			wy=(REAL)WorldToBBy(vYs[i]);
			wLeft=(REAL)WorldToBBx(vDowns[i]);
			wRight=(REAL)WorldToBBx(vUps[i]);

			m_stream<<wy<<_T(" ")<<wLeft<<_T(" ")<<wRight<<_T(" ")<<dWidth<<_T("\n");
		}
		m_stream<<n<<_T(" { EWErrorBarAH} repeat\n");
	}
	else // bAbsolute && bVertical
	{
		for (i=0;i<n;i++)
		{
			wx=(REAL)WorldToBBx(vXs[i]);
			wUp=(REAL)WorldToBBy(vUps[i]);
			wDown=(REAL)WorldToBBy(vDowns[i]);

			m_stream<<wx<<_T(" ")<<wDown<<_T(" ")<<wUp<<_T(" ")<<dWidth<<_T("\n");
		}
		m_stream<<n<<_T(" { EWErrorBarAV} repeat\n");
	}
}

}

